package com.web_bloks.mvc.client;

//import java.util.HashMap;

import com.google.gwt.core.client.GWT;

/**
 * 
 * @author Jean-Lou Dupont
 *
 */
abstract public class Facade implements IFacade {

	/**
	 * The Singleton instance of the Facade
	 */
	protected static Facade instance = null;

	/**
	 * Reference to the Controller
	 */
	protected Controller controller = null;

	/**
	 * Reference to the Model
	 */
	protected Model model = null;

	/**
	 * Reference to the View
	 */
	protected View view = null;

	/**
	 * Constructor.

	 * @throws RuntimeException
	 *             Error if Singleton instance has already been constructed
	 * 
	 */
	public Facade( )	{
		super();
		if (instance != null) 
			throw new RuntimeException("Facade already constructed");
		instance = this;
		initializeFacade();
	}

	/**
	 * Initialize the Singleton <code>Facade</code> instance.
	 */
	protected void initializeFacade( )	{
		
		initializeModel();
		initializeController();
		initializeView();
	}
	/**
	 * Facade Singleton Factory method
	 * 
	 * @return the Singleton instance of the Facade
	 */
	public static Facade getInstance( ) {
		if (instance == null) {
			throw new RuntimeException( "Facade should already be constructed" );
		}
		return instance;
	}

	/**
	 * Initialize the <code>Controller</code>.
	 */
	protected void initializeController( )	{
		
		if (this.controller != null) {
			return;
		}
		this.controller = Controller.getInstance();
	}

	/**
	 * Initialize the <code>Model</code>.
	 */
	protected void initializeModel( ) {
		
		if (this.model != null) {
			return;
		}
		this.model = Model.getInstance();
	}

	/**
	 * Initialize the <code>View</code>.
	 */
	protected void initializeView( ) {
		
		if (this.view != null) {
			return;
		}
		this.view = View.getInstance();
	}

	/**
	 * Register an <code>ICommand</code> with the <code>Controller</code> by
	 * Notification name.
	 * 
	 * @param noteName
	 *            the name of the <code>INotification</code> to associate the
	 *            <code>ICommand</code> with
	 * @param commandClassRef
	 *            a reference to the Class of the <code>ICommand</code>
	 */
	public void registerCommand( INotification note, ICommand commandClassInstance ) {
		
		this.controller.registerCommand( note, commandClassInstance );
	}

	/**
	 * Register a <code>IMediator</code> with the <code>View</code>.
	 * 
	 * @param mediator
	 *            the name to associate with this <code>IMediator</code>
	 */
	public void registerMediator( IMediator mediator ) {
		
		if (this.view != null) {
			this.view.registerMediator( mediator );
		}
	}

	/**
	 * Register an <code>IProxy</code> with the <code>Model</code> by name.
	 * 
	 * @param proxy
	 *            the name of the <code>IProxy</code> instance to be
	 *            registered with the <code>Model</code>.
	 */
	public void registerProxy( IProxy proxy ) {
		
		this.model.registerProxy( proxy );
	}

	/**
	 * Retrieve an <code>IMediator</code> from the <code>View</code>.
	 * 
	 * @param mediatorName
	 * @return the <code>IMediator</code> previously registered with the given
	 *         <code>mediatorName</code>.
	 */
	public IMediator retrieveMediator( String mediatorName ) {
		
		return this.view.retrieveMediator( mediatorName );
	}

	/**
	 * Retrieve an <code>IProxy</code> from the <code>Model</code> by name.
	 * 
	 * @param proxyName
	 *            the name of the proxy to be retrieved.
	 * @return the <code>IProxy</code> instance previously registered with the
	 *         given <code>proxyName</code>.
	 */
	public IProxy retrieveProxy( String proxyName ) {
		
		return this.model.retrieveProxy( proxyName );
	}

	/**
	 * Create and send an <code>INotification</code>.
	 * 
	 * <P>
	 * Keeps us from having to construct new notification 
	 * instances in our implementation code.
	 * @param notificationName the name of the notiification to send
	 * @param body the body of the notification (optional)
	 * @param type the type of the notification (optional)
	 */ 
	public void sendNotification( String notificationName, NotificationBody body, String type )  {
		
		Notification notif = (Notification) GWT.create( Notification.class );
		notif.init(notificationName, body, type);
		//notifyObservers( new Notification( notificationName, body, type ) );
		notifyObservers( notif );
	}

	/**
	 * Notify <code>Observer</code>s.
	 * 
	 * @param notification
	 *            the <code>INotification</code> to have the <code>View</code>
	 *            notify <code>Observers</code> of.
	 */
	public void notifyObservers( INotification notification ) {
		
		if (this.view != null) {
			this.view.notifyObservers( notification );
		}
	}

	
}//END